#[macro_use]
extern crate bencher;

use bencher::Bencher;
use rust_ecc::ccbinds::{c_mod_inverse, c_sm2p_mult, c_sm2p_reduction};
use rust_ecc::ccbinds::{c_sm2p_recover, c_sm2p_sign, c_sm2p_verify};
use rust_ecc::ecc_const::{SM2_B, SM2_GX, SM2_GY};
use rust_ecc::ecc_const::{SM2_N, SM2_N_K0, SM2_N_RR, SM2_P, SM2_P_K0, SM2_P_RR};
use rust_ecc::ecc_key::{ec_recover, ec_verify, PrivateKey};
#[allow(unused_imports)]
use rust_ecc::mont::{mont_mult, mont_reduction, sm2p_mult, sm2p_reduction};
#[cfg(feature = "asm")]
use rust_ecc::mont::{sm2p_mult_asm, sm2p_reduction_asm, sm2p_sqr_asm};
use rust_ecc::test_data::tests::*;
use rust_ecc::U256;
use rust_ecc::{CurveSM2, TypeSM2};
#[allow(unused_imports)]
use rust_ecc::{Mont, MontSM2p, Montgomery};

fn u256_add_1k(bench: &mut Bencher) {
    bench.iter(|| {
        for _i in 0..1000 {
            let (_r1, _) = dx1.add(&dx1);
        }
    })
}

fn u256_lshift1_1k(bench: &mut Bencher) {
    bench.iter(|| {
        for _i in 0..1000 {
            let mut x1 = dx1.clone();
            let _ = x1.lshift1();
        }
    })
}

fn cmod_inverse(bench: &mut Bencher) {
    bench.iter(|| {
        let _r1 = c_mod_inverse(&dx1, &SM2_P);
    })
}

fn csm2p_reduction(bench: &mut Bencher) {
    bench.iter(|| {
        let _r1 = c_sm2p_reduction(&dx1_m);
    })
}

fn csm2p_mult(bench: &mut Bencher) {
    bench.iter(|| {
        let _r1 = c_sm2p_mult(&dx1, &SM2_P_RR);
    })
}

fn csm2p_sign(bench: &mut Bencher) {
    let curve = CurveSM2::new("sm2p");
    let pk = PrivateKey::new(&curve);
    let privk = pk.private_key();
    let msg = U256::random();
    bench.iter(|| {
        let (_r, _s, _is_odd) = c_sm2p_sign(&msg, privk);
    })
}

fn csm2p_verify(bench: &mut Bencher) {
    let curve = CurveSM2::new("sm2p");
    let pk = PrivateKey::new(&curve);
    let privk = pk.private_key();
    let (pubx, puby) = pk.public_key();
    let msg = U256::random();
    let (r, s, _is_odd) = c_sm2p_sign(&msg, privk);
    bench.iter(|| {
        let _ = c_sm2p_verify(&r, &s, &msg, &pubx, &puby);
    })
}

fn csm2p_recover(bench: &mut Bencher) {
    let curve = CurveSM2::new("sm2p");
    let pk = PrivateKey::new(&curve);
    let privk = pk.private_key();
    let msg = U256::random();
    let (r, s, is_odd) = c_sm2p_sign(&msg, privk);
    bench.iter(|| {
        let (_px, _py, _ok) = c_sm2p_recover(&r, &s, &msg, is_odd);
    })
}

fn r_mod_inverse(bench: &mut Bencher) {
    bench.iter(|| {
        let _r1 = dx1.mod_inverse(&SM2_P);
    })
}

fn r_sm2p_reduction(bench: &mut Bencher) {
    bench.iter(|| {
        let _r1 = sm2p_reduction(&dx1_m);
    })
}

fn r_sm2p_mult(bench: &mut Bencher) {
    bench.iter(|| {
        let _r1 = sm2p_mult(&dx1, &SM2_P_RR);
    })
}

#[allow(dead_code)]
#[cfg(feature = "asm")]
fn r_sm2p_mult_asm(bench: &mut Bencher) {
    bench.iter(|| {
        let _r1 = sm2p_mult_asm(&dx1, &SM2_P_RR);
    })
}

#[allow(dead_code)]
#[cfg(feature = "asm")]
fn r_sm2p_sqr_asm(bench: &mut Bencher) {
    bench.iter(|| {
        let _r1 = sm2p_sqr_asm(&dx1);
    })
}

fn r_sm2_mult(bench: &mut Bencher) {
    bench.iter(|| {
        let _r1 = mont_mult::<SM2_P_K0>(&dx1, &SM2_P_RR, &SM2_P);
    })
}

fn r_sm2n_mult(bench: &mut Bencher) {
    bench.iter(|| {
        let _r1 = mont_mult::<SM2_N_K0>(&dx1, &SM2_N_RR, &SM2_N);
    })
}

fn r_mont_reduction(bench: &mut Bencher) {
    //let mont: Mont = Mont::new(&SM2_P);
    bench.iter(|| {
        //let _r1 = mont.reduction(&dx1_m);
        let _r1 = mont_reduction::<1>(&dx1_m, &SM2_P);
    })
}

fn r_fermat_inverse(bench: &mut Bencher) {
    let mont: Mont = Mont::new(&SM2_P);
    bench.iter(|| {
        let _r1 = mont.inverse(&dx1);
    })
}

fn r_fermat_sm2p_inverse(bench: &mut Bencher) {
    let mont = MontSM2p::new();
    bench.iter(|| {
        let _r1 = mont.inverse(&dx1);
    })
}

fn r_sm2_sqrt(bench: &mut Bencher) {
    let mont: Mont = Mont::new(&SM2_P);
    bench.iter(|| {
        let _r1 = mont.sqrt(&dx1_sq);
    })
}

fn r_sm2p_sqrt(bench: &mut Bencher) {
    let mont = MontSM2p::new();
    bench.iter(|| {
        let _r1 = mont.sqrt(&dx1_sq);
    })
}

#[allow(dead_code)]
#[cfg(feature = "asm")]
fn r_sm2p_reduction_asm(bench: &mut Bencher) {
    bench.iter(|| {
        let _r1 = sm2p_reduction_asm(&dx1_m);
    })
}

fn u256_random(bench: &mut Bencher) {
    bench.iter(|| {
        let _r1 = U256::random();
    })
}

fn r_sm2p_sign(bench: &mut Bencher) {
    let curve = CurveSM2::new("sm2p");
    let pk = PrivateKey::new(&curve);
    let msg = U256::random();
    bench.iter(|| {
        let (_r, _s, _is_odd) = pk.sign(&curve, &msg);
    })
}

fn r_sm2p_recover(bench: &mut Bencher) {
    let curve = CurveSM2::new("sm2p");
    let pk = PrivateKey::new(&curve);
    let msg = U256::random();
    let (r, s, is_odd) = pk.sign(&curve, &msg);
    bench.iter(|| {
        let (_px, _py, _ok) = ec_recover(&curve, &r, &s, &msg, is_odd);
    })
}

fn r_sm2p_verify(bench: &mut Bencher) {
    let curve = CurveSM2::new("sm2p");
    let pk = PrivateKey::new(&curve);
    let (pubx, puby) = pk.public_key();
    let msg = U256::random();
    let (r, s, _is_odd) = pk.sign(&curve, &msg);
    bench.iter(|| ec_verify(&curve, &r, &s, &pubx, &puby, &msg))
}

fn r_sm2_sign(bench: &mut Bencher) {
    let curve: TypeSM2 = TypeSM2::new(&SM2_P, &SM2_N, &SM2_B, &SM2_GX, &SM2_GY, "sm2-n3");
    let pk = PrivateKey::new(&curve);
    let msg = U256::random();
    bench.iter(|| {
        let (_r, _s, _is_odd) = pk.sign(&curve, &msg);
    })
}

fn r_sm2_verify(bench: &mut Bencher) {
    let curve: TypeSM2 = TypeSM2::new(&SM2_P, &SM2_N, &SM2_B, &SM2_GX, &SM2_GY, "sm2-n3");
    let pk = PrivateKey::new(&curve);
    let (pubx, puby) = pk.public_key();
    let msg = U256::random();
    let (r, s, _is_odd) = pk.sign(&curve, &msg);
    bench.iter(|| ec_verify(&curve, &r, &s, &pubx, &puby, &msg))
}

fn r_sm2_recover(bench: &mut Bencher) {
    let curve: TypeSM2 = TypeSM2::new(&SM2_P, &SM2_N, &SM2_B, &SM2_GX, &SM2_GY, "sm2-n3");
    let pk = PrivateKey::new(&curve);
    let msg = U256::random();
    let (r, s, is_odd) = pk.sign(&curve, &msg);
    bench.iter(|| {
        let (_px, _py, _ok) = ec_recover(&curve, &r, &s, &msg, is_odd);
    })
}

benchmark_group!(
    benches,
    u256_add_1k,
    u256_lshift1_1k,
    cmod_inverse,
    csm2p_reduction,
    csm2p_mult,
    csm2p_sign,
    csm2p_verify,
    csm2p_recover,
    r_mod_inverse,
    u256_random,
    r_mont_reduction,
    r_sm2_sqrt,
    r_sm2p_sqrt,
    r_fermat_inverse,
    r_fermat_sm2p_inverse,
    r_sm2p_reduction,
    r_sm2p_mult,
    r_sm2n_mult,
    r_sm2_mult,
    r_sm2p_sign,
    r_sm2p_verify,
    r_sm2p_recover,
    r_sm2_sign,
    r_sm2_verify,
    r_sm2_recover,
);

#[cfg(feature = "asm")]
benchmark_group!(
    benches_asm,
    r_sm2p_mult_asm,
    r_sm2p_sqr_asm,
    r_sm2p_reduction_asm
);

#[cfg(feature = "asm")]
benchmark_main!(benches, benches_asm);
#[cfg(not(feature = "asm"))]
benchmark_main!(benches);
